package mod

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"golang.org/x/mod/modfile"
)

var ErrSkip = errors.New("skip")

type tx = modfile.File //hide it

type File struct {
	path string
	*tx
}

func Update(fn string, do func(modFile *File) error) error {
	modFile, err := Open(fn)
	if err != nil {
		return err
	}

	if err := do(modFile); err != nil {
		if err == ErrSkip {
			return nil
		}
		return errors.WithStack(err)
	}

	return modFile.Save()
}

func Open(path string) (*File, error) {
	path = fixModFn(path)
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	if mod, err := modfile.Parse(path, data, nil); err != nil {
		return nil, errors.WithStack(err)
	} else {
		return &File{tx: mod, path: path}, nil
	}
}

func (modFile *File) IsNil() bool {
	return modFile == nil || modFile.tx == nil
}

func (modFile File) Save() error {
	if data, err := modFile.Format(); err != nil {
		return errors.WithStack(err)
	} else {
		return errors.WithStack(os.WriteFile(modFile.path, data, 0666))
	}
}

func (modFile File) Path() string {
	return modFile.path
}

func fixModFn(path string) string {
	if !strings.HasSuffix(path, ".mod") {
		path = filepath.Join(path, "go.mod")
	}
	return path
}
